package etcd

import (
	"context"
	"fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
	"math/rand"
	"os"
	"strings"
	"time"
)

const RegisterPrefix = "/srv/reg"

type ServiceRegister struct {
	*EtcdV3Wrapper

	leaseTime int64
	leaseID   clientv3.LeaseID
	leaseCh   <-chan *clientv3.LeaseKeepAliveResponse

	rInfo *ServiceRegisterInfo
}

func RegisterService(endpoints string, srName string, srConnect string, leaseTime int64) *ServiceRegister {

	wp, err := NewEtcdV3Wrapper(endpoints, 3, 3)

	if err != nil {
		panic(err)
	}
	register := &ServiceRegister{
		EtcdV3Wrapper: wp,
	}
	rInfo := NewRegisterInfo()
	rInfo.SrName = srName
	rInfo.SrInvoke = srConnect
	rInfo.LeaseTime = leaseTime

	cInfo := strings.Split(srConnect, ":")
	rInfo.RequestIp = cInfo[0]
	rInfo.Port = cInfo[1]

	leaseResp, err := wp.cli.Grant(context.Background(), leaseTime)
	if err != nil {
		panic(err)
	}

	k := register.registerPath(srName)
	v := rInfo.String()
	_, err = wp.cli.Put(context.Background(), k, v, clientv3.WithLease(leaseResp.ID))
	if err != nil {
		panic(err)
	}

	leaseCh, err := wp.cli.KeepAlive(context.Background(), leaseResp.ID)
	if err != nil {
		panic(err)
	}

	register.leaseTime = leaseTime
	register.leaseID = leaseResp.ID
	register.leaseCh = leaseCh
	register.rInfo = rInfo

	return register
}

func (srr *ServiceRegister) registerPath(srName string) string {
	rand.Seed(time.Now().UnixNano())
	hostname, _ := os.Hostname()

	path := fmt.Sprintf("%s/%s/%s_%s",
		RegisterPrefix, srName,
		hostname, srr.rInfo.Port,
	)

	return path
}

func (srr *ServiceRegister) ListenLease() {
	for {
		_, ok := <-srr.leaseCh
		now := time.Now().Format(time.DateTime)
		if ok {
			//srr.log("leaseTime keep live success %s", now)
		} else {
			t := 3
			srr.log("leaseTime keep live fail %s,will try at %ds", now, t)
			time.Sleep(time.Duration(t) * time.Second)
		}
	}
}

func (srr *ServiceRegister) Close() {
	_, err := srr.cli.Revoke(context.Background(), srr.leaseID)
	if err != nil {
		panic(err)
	}
	srr.cli.Close()

	srr.log("service register closed")
}

func (srr *ServiceRegister) log(s string, args ...interface{}) {
	if !strings.HasSuffix(s, "\n") {
		s = s + "\n"
	}
	fmt.Printf("[ETCD ServiceRegister]"+s, args...)
}
